package org.example.springaop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Aspect
public class OperationLogAspect {

    // @annotation not works on composed annotation
    // https://stackoverflow.com/questions/78297670/spring-aop-annotation-not-works-on-composed-annotation
    // https://stackoverflow.com/a/67005346/1082681

    // `within(@OperationLog *)` 匹配带有 @OperationLog 注解的类，相当于 @within(OperationLog)
    // `within(@(OperationLog *) *)` 匹配注解中带有 @OperationLog 元注解的类
    // `within(@(@(OperationLog *) *) *)` 匹配注解的元注解中带有 @OperationLog 元注解的类
    // `execution(* *(..))` 匹配任意方法
    // `execution(@OperationLog * *(..))` 匹配带有 @OperationLog 注解的方法，相当于 @annotation(OperationLog)
    // `execution(@(OperationLog *) * *(..))` 匹配注解中带有 @OperationLog 元注解的方法
    // `execution(@(@(OperationLog *) *) * *(..))` 匹配注解的元注解中带有 @OperationLog 元注解的方法

    @Pointcut("within(@OperationLog *) || " +
            "within(@(@OperationLog *) *) || " +
            "execution(@OperationLog * *(..)) ||" +
            "execution(@(@OperationLog *) * *(..))")
    public void typeOrMethod() {
    }

    @Before("typeOrMethod()")
    public void beforeTypeOrMethod(JoinPoint point) {
        Logger log = getAspectLogger(point);
        log.info("before handle: " + point.getSignature());
    }

    private static final Logger _log = LoggerFactory.getLogger(OperationLogAspect.class);

    private static AspectLogger getAspectLogger(JoinPoint pjp) {
        return new AspectLogger(_log, pjp);
    }
}
